using System;
using System.ComponentModel;
using System.Runtime.Serialization;

using SharpGL.Media3D;
using SharpGL.SceneGraph;
using SharpGL.Enumerations;

namespace SharpGL.OpenGLAttributes
{
    /// <summary>
    /// This class has all the settings you can edit for current.
    /// </summary>
    [TypeConverter(typeof(System.ComponentModel.ExpandableObjectConverter))]
    [DataContract(/*IsReference = true, */Name = "CurrentAttributes", Namespace = "SharpGL.SceneGraph")]
    public class CurrentAttributes : OpenGLAttributes
    {
        #region Private Consts

        private static readonly AttributeMask attributeMask = AttributeMask.Current;

        #endregion Private Consts

        #region Private Fields

        [DataMember()]
        private GLColor? currentColor;
        [DataMember()]
        private int? currentColorIndex;
        [DataMember()]
        private Vector3D? currentNormalVector;
        [DataMember()]
        private UV? currentTextureCoordiate;
        [DataMember()]
        private Point3D? currentRasterPosition;
        [DataMember()]
        private GLColor? currentRasterColor;
        [DataMember()]
        private int? currentRasterColorIndex;
        [DataMember()]
        private UV? currentRasterTextureCoordiate;
        [DataMember()]
        private bool? currentEdgeFlag;

        #endregion Private Fields

        #region Protected Methods

        protected override void OnDeserializing()
        {
            AttributeFlags = attributeMask;
        }

        #endregion Protected Methods

        #region Public Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="CurrentAttributes"/> class.
        /// </summary>
        public CurrentAttributes()
        {
            AttributeFlags = attributeMask;
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Returns true if any attributes are set.
        /// </summary>
        /// <returns>
        /// True if any attributes are set
        /// </returns>
        public override bool AreAnyAttributesSet()
        {
            return (
                    currentColor.HasValue ||
                    currentColorIndex.HasValue ||
                    currentNormalVector != null ||
                    currentTextureCoordiate != null ||
                    currentRasterPosition != null ||
                    currentRasterColor.HasValue ||
                    currentRasterColorIndex.HasValue ||
                    currentRasterTextureCoordiate != null ||
                    currentEdgeFlag.HasValue);

        }

        /// <summary>
        /// Reset all attributes to unset state.
        /// </summary>
        public override void ResetAllAttributes()
        {
            CurrentColor = null;
            CurrentColorIndex = null;
            CurrentNormalVector = null;
            CurrentTextureCoordiate = null;
            CurrentRasterPosition = null;
            CurrentRasterColor = null;
            CurrentRasterColorIndex = null;
            CurrentRasterTextureCoordiate = null;
            CurrentEdgeFlag = null;
        }

        /// <summary>
        /// Sets the attributes.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        public override void SetAttributes(OpenGL gl)
        {
            if (currentColor.HasValue) gl.Color(currentColor.Value.R, currentColor.Value.G, currentColor.Value.B, currentColor.Value.A);
            if (currentColorIndex.HasValue) gl.Index(currentColorIndex.Value);
            if (currentNormalVector != null) gl.Normal(currentNormalVector.Value.X, currentNormalVector.Value.Y, currentNormalVector.Value.Z);
            if (currentTextureCoordiate != null) gl.TexCoord(currentTextureCoordiate.Value.U, currentTextureCoordiate.Value.V);
            if (currentRasterPosition != null) gl.RasterPos(currentRasterPosition.Value.X, currentRasterPosition.Value.X);
            //todoif (currentRasterColor.HasValue) gl.(currentColor.Value.R, currentColor.Value.G, currentColor.Value.b, currentColor.Value.a);
            //todoif (currentRasterColorIndex != null) gl.(currentColor.R, currentColor.G, currentColor.b, currentColor.a);
            //todoif (currentRasterTextureCoordiate != null) gl.(currentColor.R, currentColor.G, currentColor.b, currentColor.a);
            if (currentEdgeFlag.HasValue) gl.EdgeFlag(currentEdgeFlag.Value ? (byte)OpenGL.GL_TRUE : (byte)OpenGL.GL_FALSE);
        }

        #endregion Public Methods

        #region Public Properties

        /// <summary>
        /// Gets or sets the color of the current.
        /// </summary>
        /// <value>
        /// The color of the current.
        /// </value>
        [Description("CurrentColor"), Category("Current attributes")]
        public GLColor? CurrentColor
        {
            get { return currentColor; }
            set
            {
                if (currentColor != value)
                {
                    currentColor = value;

                    NotifyPropertyChanged("CurrentColor");
                }
            }
        }

        /// <summary>
        /// Gets or sets the index of the current color.
        /// </summary>
        /// <value>
        /// The index of the current color.
        /// </value>
        [Description("CurrentColorIndex"), Category("Current attributes")]
        public int? CurrentColorIndex
        {
            get { return currentColorIndex; }
            set
            {
                if (currentColorIndex != value)
                {
                    currentColorIndex = value;

                    NotifyPropertyChanged("CurrentColorIndex");
                }
            }
        }

        /// <summary>
        /// Gets or sets the current normal point.
        /// </summary>
        /// <value>
        /// The current normal point.
        /// </value>
        [Description("CurrentNormalVector"), Category("Current attributes")]
        public Vector3D? CurrentNormalVector
        {
            get { return currentNormalVector; }
            set
            {
                if (currentNormalVector != value)
                {
                    currentNormalVector = value;

                    NotifyPropertyChanged("CurrentNormalVector");
                }
            }
        }

        /// <summary>
        /// Gets or sets the current texture coordiate.
        /// </summary>
        /// <value>
        /// The current texture coordiate.
        /// </value>
        [Description("CurrentTextureCoordiate"), Category("Current attributes")]
        public UV? CurrentTextureCoordiate
        {
            get { return currentTextureCoordiate; }
            set
            {
                if (currentTextureCoordiate != value)
                {
                    currentTextureCoordiate = value;

                    NotifyPropertyChanged("CurrentTextureCoordiate");
                }
            }
        }

        /// <summary>
        /// Gets or sets the current raster position.
        /// </summary>
        /// <value>
        /// The current raster position.
        /// </value>
        [Description("CurrentRasterPosition"), Category("Current attributes")]
        public Point3D? CurrentRasterPosition
        {
            get { return currentRasterPosition; }
            set
            {
                if (currentRasterPosition != value)
                {
                    currentRasterPosition = value;

                    NotifyPropertyChanged("CurrentRasterPosition");
                }
            }
        }

        /// <summary>
        /// Gets or sets the color of the current raster.
        /// </summary>
        /// <value>
        /// The color of the current raster.
        /// </value>
        [Description("CurrentRasterColor"), Category("Current attributes")]
        public GLColor? CurrentRasterColor
        {
            get { return currentRasterColor; }
            set
            {
                if (currentRasterColor != value)
                {
                    currentRasterColor = value;

                    NotifyPropertyChanged("CurrentRasterColor");
                }
            }
        }

        /// <summary>
        /// Gets or sets the index of the current raster color.
        /// </summary>
        /// <value>
        /// The index of the current raster color.
        /// </value>
        [Description("CurrentRasterColorIndex"), Category("Current attributes")]
        public int? CurrentRasterColorIndex
        {
            get { return currentRasterColorIndex; }
            set
            {
                if (currentRasterColorIndex != value)
                {
                    currentRasterColorIndex = value;

                    NotifyPropertyChanged("CurrentRasterColorIndex");
                }
            }
        }

        /// <summary>
        /// Gets or sets the current raster texture coordiate.
        /// </summary>
        /// <value>
        /// The current raster texture coordiate.
        /// </value>
        [Description("CurrentRasterTextureCoordiate"), Category("Current attributes")]
        public UV? CurrentRasterTextureCoordiate
        {
            get { return currentRasterTextureCoordiate; }
            set
            {
                if (currentRasterTextureCoordiate != value)
                {
                    currentRasterTextureCoordiate = value;

                    NotifyPropertyChanged("CurrentRasterTextureCoordiate");
                }
            }
        }

        /// <summary>
        /// Gets or sets the current edge flag.
        /// </summary>
        /// <value>
        /// The current edge flag.
        /// </value>
        [Description("CurrentEdgeFlag"), Category("Current attributes")]
        public bool? CurrentEdgeFlag
        {
            get { return currentEdgeFlag; }
            set
            {
                if (currentEdgeFlag != value)
                {
                    currentEdgeFlag = value;

                    NotifyPropertyChanged("CurrentEdgeFlag");
                }
            }
        }

        #endregion Public Properties
    }
}
